package com.dalonedrow.engine.ui.base.panel;

import java.util.ArrayList;

import com.dalonedrow.engine.sprite.base.SimpleDimension;
import com.dalonedrow.engine.ui.base.GuiComponent;
import com.dalonedrow.engine.ui.base.border.GuiBorder;
import com.dalonedrow.globalvariables.constants.hq.GlobalConstants;

/**
 * Panel implementation with two layouts, portrait or landscape.
 * @author Donald
 */
public abstract class PagePanel extends Panel {
	/** the component alignment used when the layout is landscape. */
	private int						alignment;
	/** the list of child components. */
	private ArrayList<GuiComponent>	children;
	/** the type of layout used. */
	private int						layout;
	private int						maximumHeight;
	private int						maximumWidth;
	private int						minimumHeight;
	private int						minimumWidth;
	/** the {@link GuiComponent}'s preferred size. */
	private SimpleDimension				preferredSize;
	private int						preferredWidth;
	/** Creates a new instance of GuiPagePanel.java. */
	protected PagePanel() {
		alignment = Panel.LANDSCAPE_TOP;
		children = new ArrayList<GuiComponent>();
		preferredSize = new SimpleDimension(0, 0);
	}
	/**
	 * Creates a new instance of {@link PagePanel}.
	 * @param pageLayout the page layout, landscape or portrait
	 * @param pageAlignment the page alignment, top, bottom, left, right, center
	 */
	protected PagePanel(final int pageLayout, final int pageAlignment) {
		layout = pageLayout;
		alignment = pageAlignment;
		children = new ArrayList<GuiComponent>();
		preferredSize = new SimpleDimension(0, 0);
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final void addChild(final GuiComponent child) {
		children.add(child);
		// re-size the panel
		preferredSize.width = 0;
		preferredSize.height = 0;
		getPreferredSize();
		// re-position the children
		if (super.getPosition() != null) {
			setPosition(
					super.getPosition().getX(),
					super.getPosition().getY(),
					super.getPosition().getZ());
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final void addChild(final String name, final GuiComponent child) {
		addChild(child);
	}
	/**
	 * {@inheritDoc}
	 */
	public final void animate() {
		// TODO Auto-generated method stub

	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final GuiComponent[] getChildren() {
		return children.toArray(new GuiComponent[children.size()]);
	}
	/**
	 * Gets the page layout, portrtait or landscape.
	 * @return <code>int</code>
	 */
	protected int getLayout() {
		return layout;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public SimpleDimension getPreferredSize() {
		if (preferredSize.width == 0
				|| preferredSize.height == 0) {
			int w = 0, h = 0;
			if (getBorder() != null) {
				w = getBorder().getInsets().left;
				w += getBorder().getInsets().right;
				h = getBorder().getInsets().top;
				h += getBorder().getInsets().bottom;
			}
			w += getInsets().left + getInsets().right;
			h += getInsets().top + getInsets().bottom;
			switch (layout) {
			case Panel.PAGELAYOUT_PORTRAIT:
				int maxChildW = 0;
				for (int i = 0; i < children.size(); i++) {
					maxChildW = Math.max(maxChildW,
							children.get(i).getPreferredSize().width);
					h += children.get(i).getPreferredSize().height;
				}
				w += maxChildW;
				break;
			case Panel.PAGELAYOUT_LANDSCAPE:
				int maxChildH = 0;
				for (int i = 0; i < children.size(); i++) {
					maxChildH = Math.max(maxChildH,
							children.get(i).getPreferredSize().height);
					w += children.get(i).getPreferredSize().width;
				}
				h += maxChildH;
				break;
			default:
				break;
			}

			if (minimumHeight > 0) {
				h = Math.max(h, minimumHeight);
			}
			if (maximumHeight > 0) {
				h = Math.min(h, maximumHeight);
			}
			if (minimumWidth > 0) {
				w = Math.max(w, minimumWidth);
			}
			if (maximumWidth > 0) {
				w = Math.min(w, maximumWidth);
			}
			preferredSize.width = Math.max(w, preferredWidth);
			preferredSize.height = h;
			positionChildren();
		}
		if (getBorder() != null) {
			if (!(getBorder().getPreferredSize() != null
					&& getBorder().getPreferredSize().width
					== preferredSize.width && getBorder().getPreferredSize().height == preferredSize.height)) {
				getBorder().setPreferredSize(preferredSize.width,
						preferredSize.height);
			}
		}
		return preferredSize;
	}
	/**
	 * Gets the preferred width.
	 * @return <code>int</code>
	 */
	public int getPreferredWidth() {
		return preferredWidth;
	}
	/**
	 * {@inheritDoc}
	 */
	public final void move() {
		// TODO Auto-generated method stub

	}
	/** Positions all children. */
	private void positionChildren() {
		if (super.isDebug()) {
			System.out.println(this + ":: position at " + super.getPosition());
		}
		if (super.getPosition() != null) {
			double newX = super.getPosition().getX();
			double newY = super.getPosition().getY();
			int innerWidth = getPreferredSize().width;
			int innerHeight = getPreferredSize().height;
			// move to top of panel
			newY += innerHeight;
			if (super.getBorder() != null) {
				if (!(super.getBorder().getPosition() != null 
						&& super.getBorder().getPosition().equals(
								super.getPosition()))) {
					super.getBorder().setPosition(
							super.getPosition().getX(),
							super.getPosition().getY(),
							super.getPosition().getZ()
							);
				}
				// subtract border insets from inner width and height
				innerWidth -= getBorder().getInsets().left;
				innerWidth -= getBorder().getInsets().right;
				innerHeight -= getBorder().getInsets().top;
				innerHeight -= getBorder().getInsets().bottom;

				newX += getBorder().getInsets().left; // move right from border
				newY -= getBorder().getInsets().top; // move down from border
			}
			// subtract insets from inner width and height
			innerWidth -= getInsets().left;
			innerWidth -= getInsets().right;
			innerHeight -= getInsets().top;
			innerHeight -= getInsets().bottom;

			newX += getInsets().left; // move right
			newY -= getInsets().top; // move down
			int childrenWidths = 0;
			for (int i = 0; i < children.size(); i++) {
				childrenWidths += children.get(i).getPreferredSize().width;
			}
			double childX = 0, spacing = 0;
			switch (super.getHorizontalAlignment()) {
			case CENTER:
				childX = newX + (innerWidth - childrenWidths) / 2;
				break;
			case LEFT:
				childX = newX;
				break;
			case RIGHT:
				childX = newX + innerWidth - childrenWidths;
				break;
			default: // JUSTIFY
				childX = newX;
				spacing = (innerWidth - childrenWidths) / (children.size() - 1);
				break;
			}
			/*
			switch (layout) {
			case Panel.PAGELAYOUT_LANDSCAPE:
				break;
			case Panel.PAGELAYOUT_PORTRAIT:
				positionChildrenPortrait(newX, newY, innerWidth);
				break;
			default:
				break;
			}
			*/
			// x and y should now be at top-left corner of inner area
			if (super.isDebug()) {
				System.out.println(this + "::innerWidth " + innerWidth + "(" 
						+ getPreferredSize().width);
			}
			for (int i = 0; i < children.size(); i++) {
				GuiComponent child = children.get(i);
				switch (layout) {
				case Panel.PAGELAYOUT_LANDSCAPE:
					double childY = 0;
					switch (alignment) {
					case Panel.LANDSCAPE_CENTER:
						int offset =
								(innerHeight - child.getPreferredSize().height) / 2;
						childY = newY - innerHeight + offset;
						break;
					case Panel.LANDSCAPE_BOTTOM:
						childY = newY - innerHeight;
						break;
					default: // TOP
						childY = newY - child.getPreferredSize().height;
						break;
					} // end LANDSCAPE y-alignment check
						// POSITION CHILD FOR LANDSCAPE ALIGNMENT
					child.setPosition(
							childX,
							childY,
							super.getPosition().getZ()
									+ GlobalConstants.CHILD_STEP
							);
					switch (super.getHorizontalAlignment()) {
					case CENTER:
					case LEFT:
					case RIGHT:
						childX += child.getPreferredSize().width;
						break;
					default: // JUSTIFY
						childX += child.getPreferredSize().width + spacing;
						break;
					} // end LANDSCAPE x-alignment check
					break;
				
				  case Panel.PAGELAYOUT_PORTRAIT: 
					  // move down to child's bottom edge 
				  newY -= child.getPreferredSize().height; 
				  switch (alignment) { 
				  case Panel.PORTRAIT_CENTER: 
					  child.setPosition(
							  newX + (innerWidth - child .getPreferredSize().width) / 2,
				  newY, 
				  super.getPosition().getZ() + GlobalConstants.CHILD_STEP);
						if (super.isDebug()) {
							System.out.println(child + "::center setPosition " 
									+ child.getPosition()+"::"+child.getPreferredSize());
						}
				  break; 
				  case Panel.PORTRAIT_RIGHT: 
					  child.setPosition( newX +
				  innerWidth - child.getPreferredSize().width, newY,
				  super.getPosition().getZ() + GlobalConstants.CHILD_STEP );
						if (super.isDebug()) {
							System.out.println(child + "::center setPosition " 
									+ child.getPosition());
						}
				  break; default: // LEFT 
					  child.setPosition(newX, newY,
				  super.getPosition().getZ() + GlobalConstants.CHILD_STEP); 
						if (super.isDebug()) {
							System.out.println(child + "::center setPosition " 
									+ child.getPosition());
						}
					  break;
				  } break;
				 
				default:
					break;
				}
			} // end for
		}
	}
	private void positionChildrenLandscape() {
		// x and y should now be at top-left corner of inner area
		for (int i = 0; i < children.size(); i++) {
			GuiComponent child = children.get(i);
		}
	}
	private void positionChildrenPortrait(final double x, final double y,
			final int innerWidth) {
		if (super.isDebug()) {
			System.out.println(this + "::positionChildrenPortrait " + x + "," 
					+ y + "::" + innerWidth);
		}
		for (int i = 0; i < children.size(); i++) {
			GuiComponent child = children.get(i);
			// move down to child's bottom edge
			double newY = y;
			newY -= child.getPreferredSize().height;
			switch (alignment) {
			case Panel.PORTRAIT_CENTER:
				child.setPosition(
						x + (innerWidth - child.getPreferredSize().width) / 2,
						newY,
						super.getPosition().getZ() + GlobalConstants.CHILD_STEP
						);
				if (super.isDebug()) {
					System.out.println(child + "::center setPosition " 
							+ child.getPosition());
				}
				break;
			case Panel.PORTRAIT_RIGHT:
				child.setPosition(
						x + innerWidth - child.getPreferredSize().width,
						newY,
						super.getPosition().getZ() + GlobalConstants.CHILD_STEP
						);
				if (super.isDebug()) {
					System.out.println(child + "::right setPosition " 
							+ child.getPosition());
				}
				break;
			default: // LEFT
				child.setPosition(
						x,
						newY,
						super.getPosition().getZ() + GlobalConstants.CHILD_STEP);
				if (super.isDebug()) {
					System.out.println(child + "::left setPosition " 
							+ child.getPosition());
				}
				break;
			}
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setBorder(final GuiBorder newBorder) {
		super.setBorder(newBorder);
		preferredSize.width = 0;
		preferredSize.height = 0;
		getPreferredSize();
	}
	/**
	 * Sets the component alignment used when the layout is landscape.
	 * @param alignment the ComponentLAlignment to set
	 */
	public final void setLandscapeAlignment(final int pageAlignment) {
		alignment = pageAlignment;
	}
	/**
	 * Sets the maximum size.
	 * @param w the maximum width
	 * @param h the maximum height
	 */
	public void setMaximumSize(final int w, final int h) {
		maximumWidth = w;
		maximumHeight = h;
		preferredSize.width = 0;
		preferredSize.height = 0;
		getPreferredSize();
	}
	/**
	 * Sets the maximum width.
	 * @param w the maximum width
	 */
	public void setMaximumWidth(final int w) {
		maximumWidth = w;
		preferredSize.width = 0;
		preferredSize.height = 0;
		getPreferredSize();
	}
	/**
	 * Sets the minimum height.
	 * @param h the minimum height
	 */
	public void setMinimumHeight(final int h) {
		minimumHeight = h;
		preferredSize.width = 0;
		preferredSize.height = 0;
		getPreferredSize();
	}
	/**
	 * Sets the minimum size.
	 * @param w the minimum width
	 * @param h the minimum height
	 */
	public void setMinimumSize(final int w, final int h) {
		minimumWidth = w;
		minimumHeight = h;
		preferredSize.width = 0;
		preferredSize.height = 0;
		getPreferredSize();
	}
	/**
	 * Sets the minimum width.
	 * @param w the minimum width
	 */
	public void setMinimumWidth(final int w) {
		minimumWidth = w;
		preferredSize.width = 0;
		preferredSize.height = 0;
		getPreferredSize();
	}
	/**
	 * Sets the component alignment used when the layout is portrait.
	 * @param alignment the ComponentPAlignment to set
	 */
	public final void setPortraitAlignment(final int pageAlignment) {
		alignment = pageAlignment;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final void setPosition(final double x, final double y,
			final double z) {
		super.setPosition(x, y, z);
		// position all children
		positionChildren();
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setPreferredSize(final int width, final int height) {
		preferredSize.width = width;
		preferredSize.height = height;
		if (super.getBorder() != null) {
			super.getBorder().setPreferredSize(width, height);
		}
	}
	/**
	 * Sets the preferredWidth
	 * @param val the preferredWidth to set
	 */
	public void setPreferredWidth(int val) {
		preferredWidth = val;
		preferredSize.width = 0;
		getPreferredSize();
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final void setVisible(final boolean value) {
		super.setVisible(value);
		if (super.getBorder() != null) {
			super.getBorder().setVisible(value);
		}
		for (int i = 0; i < children.size(); i++) {
			children.get(i).setVisible(value);
		}
	}
}
